<template>
  <div
    v-show="mappingProps.visible"
    class="t-anchor_div"
    :class="{
      'z-sticky': isSticky,
    }"
    :style="anchor_divStyle"
  >
    <!-- 锚点组件 -->

    <!-- 顶部情况下，用标签页形式实现 -->
    <div
      v-if="position == 'top'"
      class="t-anchorTop"
      :class="[
        {
          'e-mobile': false && isMobile,
          'z-fixed': mappingProps.isFixed && mappingProps.position == 'top',
        },
        mappingProps.class,
      ]"
      :style="mappingProps.style"
    >
      <t-tabs
        :staticItems="
          (displayAnchorList || []).map(({ name }, index) => ({
            label: name,
            code: index,
          }))
        "
        class="tr-tabs-level1"
        tabPosition="top"
        :type="mappingProps.type"
        fillMode="fixedHeight"
        fillMarginBottom="20px"
        :hideTabLabel="false"
        :hideTabPanel="true"
        :activeColor="activeColor"
        visibleSeparator
        :separatorColor="isMobile ? '#f0f2f5' : undefined"
        :separatorSize="isMobile ? '10px' : undefined"
        style="margin-top: 0px"
        :tabIndex="mappingProps.tabIndex"
        :modelValue="currentAnchorIndex"
        @update:modelValue="handleChangeTab"
      >
      </t-tabs>
    </div>

    <!-- 左右情况，参考标准1.2锚点样式实现 -->
    <div
      v-else
      class="t-anchor"
      @click="crinkly = false"
      :class="[
        {
          'e-mobile': false && isMobile,
          'z-hide': isMobile && crinkly,
          'z-fixed': mappingProps.isFixed,
          'z-left': position == 'left',
        },
        mappingProps.class,
      ]"
      :style="mappingProps.style"
    >
      <div
        class="t-anchor-wrap"
        :class="{
          'f-left': position == 'left',
          'f-right': position == 'right',
        }"
      >
        <!-- 浮动的小块 -->
        <i
          class="i-square"
          v-if="mappingProps.bottomType == 'square'"
          :style="{
            top: currentAnchorIndex * 29 + 25 + 'px',
            backgroundColor: activeColor,
            borderColor: activeColor,
          }"
        ></i>
        <div
          class="anchor"
          v-for="(item, index) in displayAnchorList"
          :class="{
            'z-on': currentAnchorIndex == index,
            's-square': mappingProps.bottomType == 'square',
          }"
          :style="{
            color: currentAnchorIndex == index ? activeColor : '',
          }"
          @click="handleChangeTab(index)"
          @keyup.enter="handleChangeTab(index)"
          :title="item.name"
          :tabIndex="mappingProps.tabIndex"
        >
          <i
            class="i-dot"
            :style="{
              backgroundColor: currentAnchorIndex == index ? activeColor : '',
              borderColor: currentAnchorIndex == index ? activeColor : '',
            }"
          ></i>
          <!-- <q-icon v-if="item.icon" :name="item.icon"></q-icon> -->
          {{ item.name }}
        </div>
      </div>
    </div>
  </div>
</template>

<!-- ts只是方便开发提示和补全代码，没有用语法 -->

<script setup type="typescript">
import { computed, onMounted, useAttrs, ref, watch, reactive } from 'vue';
// 钩子函数、小工具
import { useQuasar } from '@teld/q-components';
import useMappingProps from 't/common/hooks/useMappingProps';
import {
	commonProps
} from 't/common/utils';
// 组件
import QTabs from '@teld/q-components/Tabs';
import { QTab } from '@teld/q-components/Tabs';
// 锚点实体类
import AnchorEntities from './anchor.entities.js';

const Funcs = window.Funcs || {
  GetTerms: (c, n) => n,
};

const $q = useQuasar();
// 浏览宽度低于768px
const isMobile = computed(() => $q.screen.xs || $q.platform.is.mobile);

// 是否设计时
const inDesign = !!window['fas']?.inDesign;

// 直接映射透传qursor的属性
const attrs = useAttrs();
// 组件传参
const props = defineProps(
	// 大小写不敏感
	{
		...commonProps,

		// 是否可见
		visible: {
			type: Boolean,
			default: true
		},
		// tabIndex，tab键盘响应设置，数值越大，响应越后置
		tabIndex: {
			type: [Number, String],
			default: 1
		},
		// 显示位置：right/left/top
		position: {
			type: String,
			default: 'right'
		},
		// 风格类型：none/shadow/bordered
		type: {
			type: String,
			default: 'none'
		},
		// 选中效果，块状square 圆点circle
		bottomType: {
			type: String,
			default: 'circle'
		},
		// 固定模式 true/false
		isFixed: {
			type: Boolean,
			default: false
		},
		style: {
			type: Object,
			default: () => ({})
		},
		class: {
			type: Object,
			default: () => ({})
		},
		// 锚点列表 name:名称 node:要定位锚点的节点
		staticItems: {
			type: Array,
			default: () => [],
		},
		// 滚动偏移量 锚点识别的提前量
		scrollOffset: {
			type: Number,
			default: 20
		},
		// 移动端是否粘性布局
		isSticky: {
			type: Boolean,
			default: false
		},
		// 粘性布局top
		stickyTop: String,
		// 选中颜色
		activeColor: {
			type: String,
			// default: () =>
			// 	window
			// 		?.getComputedStyle(document.documentElement, ':root')
			// 		?.getPropertyValue('--t-color')
			// 		?.trim() || 'rgb(0, 120, 212)',
		},
	}
);
// 大写首字母属性
const [mappingProps, mappingExpose] = useMappingProps(props);

// ================== 回调事件 ===================
// 触发的emit事件
const emit = defineEmits(['change']);

// 移动端下也会默认顶部黏性样式
const position = computed(() => {
	const { position } = mappingProps;
	return isMobile.value ? 'top' : position;
});

// 是否启用粘性布局
const isSticky = computed(() => (
	// 左右布局，且固定模式
	(
		position.value === 'top' &&
		mappingProps.isSticky
	)
));

// 最外部容器样式
const anchor_divStyle = computed(() => {
	return isSticky.value
		? {
			top: mappingProps.stickyTop ?? '0px'
		}
		: {};
});

const activeColor = computed(() => {
	const { activeColor } = mappingProps;
	if (!activeColor || activeColor === 'default') return 'teld_primary';
	return activeColor;
});

const anchorList = computed(() => {
	return mappingProps.staticItems.map(({ label, widget, icon, ValueInfo_label }) => {
		let node = widget?.$el instanceof HTMLElement ? widget?.$el : widget;
		if (inDesign && typeof widget === 'string' && widget.startsWith('Widget.')) {
			node = document.querySelector(`[instancecode="${widget.replace('Widget.', '')}"]`)
		}
		return {
			name: Funcs.GetTerms(label == '锚点' ? 'Schema.Controls.fasr_anchor.anchor' : ValueInfo_label, label),
			node,
			icon
		}
	})
})

const hiddenAnchorIndexs = reactive(new Set([]));
// 移动到对应节点
function moveTo(index) {
	handleChangeTab(index)
}
// 隐藏某个节点
function hideNode(index) { hiddenAnchorIndexs.add(index) }
// 显示某个节点
function showNode(index) { hiddenAnchorIndexs.delete(index) }
// ================== 要暴露的方法 ===================
defineExpose({ ...mappingExpose, moveTo, hideNode, showNode });

// 需要显示的锚点列表 displayAnch1orList
const displayAnchorList = computed(() => {
	return anchorList.value.filter((v, index) => !hiddenAnchorIndexs.has(index))
});

// 当前节点index
let currentAnchorIndex = ref(0);
// 是否缩到边上，移动设备上使用
let crinkly = ref(true);

// 定义锚点功能实例
const entities = new AnchorEntities();

// 停止触发界面滚动的回调
let stopIntersectCall = false;
let stopIntersectCallLastTime = 0;
// 初始化实体
function initEntities() {
	entities.init(displayAnchorList.value.map(v => v.node), mappingProps.scrollOffset, (intersectList, scrollDirection) => {
		if (stopIntersectCall) return;

		if (intersectList.length > 0) {
			const index = scrollDirection === 'bottom' ? Math.min(...intersectList) : Math.min(...intersectList);
			currentAnchorIndex.value = index;
			emit('change', { currentAnchorIndex: index, sourceType: 'scroll' })
		}
	});
}

function scrollToNode(index) {
	entities?.scrollToNode(index)
}

// 异步函数，等待多少毫秒
const afterTime = (cd = 0) => new Promise(reslove => setTimeout(reslove, cd));
// tab模式：切换tab事件
async function handleChangeTab(index) {
	const time = new Date().getTime();
	stopIntersectCallLastTime = time;
	stopIntersectCall = true;
	scrollToNode(index)

	await afterTime(500);
	if (stopIntersectCallLastTime == time) {
		stopIntersectCall = false;
		currentAnchorIndex.value = index;
		emit('change', { currentAnchorIndex: index, sourceType: 'click' })
	}
}

// 生命周期：组件挂载
onMounted(() => {
	initEntities();
})

//  监听对象改变，重新初始化
watch(displayAnchorList, () => {
	initEntities();
})
</script>

<style lang="scss">
@import './index.scss';
</style>
